package com.sziit.se.highconcurrency.common.security;

import com.sziit.se.highconcurrency.common.tool.EncodeUtils;
import com.sziit.se.highconcurrency.common.tool.RedisUtils;
import com.sziit.se.highconcurrency.common.annotation.IgnoreCheck;
import com.sziit.se.highconcurrency.common.annotation.Permission;
import com.sziit.se.highconcurrency.common.constant.Constants.ResponseCode;
import com.sziit.se.highconcurrency.common.exception.CustomException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

//@Component
public class SecurityInterceptor extends HandlerInterceptorAdapter {

    private final RedisUtils redisUtils;

    @Autowired
    SecurityInterceptor(RedisUtils redisUtils) {
        this.redisUtils = redisUtils;
    }

    /**
     * 拦截器，在Controller处理之前调用
     *
     * @param request  servlet请求体
     * @param response servlet响应体
     * @param handler  被调用的方法
     * @return 返回值为true继续链式调用，为false结束调用
     * @throws Exception 抛出异常提醒调用者
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();

        /*检查是否有@IgnoreCheck注解*/
        IgnoreCheck annotation = method.getAnnotation(IgnoreCheck.class);
        if (Objects.nonNull(annotation)) {
            return true;
        }

        /*从请求头获取token，检查是否为空*/
        String token = request.getHeader("Authorization");
        if (Objects.isNull(token)){
            throw new CustomException(ResponseCode.UNAUTHORIZED, "身份认证失败,token为空");
        }

        /*解析token获取用户信息*/
        CurrentUserInfo currentUserInfo = EncodeUtils.tokenDecode(token);

        /*检查用户token是否有效*/
        String key = redisUtils.generatorKey(currentUserInfo.getUserId(), currentUserInfo.getClientType());
        if (!checkToken(key, token) && redisUtils.expire(key, 6, TimeUnit.HOURS)) {
            throw new CustomException(ResponseCode.UNAUTHORIZED, "身份认证失败,无效token");
        }

        /*权限校验*/
        Permission permission = method.getAnnotation(Permission.class);
        if (Objects.nonNull(permission)){
            //TODO 权限校验逻辑
        }

        /*存储用户信息*/
        request.setAttribute("CurrentUserInfo", currentUserInfo);
        return true;
    }

    /**
     * 检查token是否与redis中的一致
     *
     * @param key   键
     * @param token token
     * @return 结果
     */
    private boolean checkToken(String key, String token) {
        String redisToken = redisUtils.get(key);
        return Objects.equals(redisToken, token);
    }
}
